/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *            Copyright (C) 2018 Institute of Computing Technology, CAS
 *               Author : Han Shukai (email : hanshukai@ict.ac.cn)
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *                  The shell acts as a task running in user mode.
 *       The main function is to make system calls through the user's output.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * */

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>

#define SHELL_BEGIN 20

#define cmd_nums    10  // the max commands shell can handle
#define cmd_args    10  // the max args the shell can accept
#define CMD_NUM     4   // the types of the cmd
                        // 1 exec
                        // 2 waitpid
                        // 3 kill
typedef void (*function)(void *parameter);

static int procnums = 6; // the num of the runable tasks
int 
my_atoi(char * num_string)
{
    int result = 0;
    int i = 0;
    while(num_string[i]){
        result = num_string[i] - '0' + 10 * result;
        i += 1;
    }
    return result;
}
// -1: unnormal return, unknown cmd
// normal return: the pid
pid_t 
shell_exec(char *taskid)
{   
    int get_the_taskid = my_atoi(taskid);
    int pid = 0;
    if(get_the_taskid > procnums){
        printf("Error, the unkown command\n");
        return -1; 
    }else{
        int id = get_the_taskid;
        int printlocation = 6;
        int argc = 3;
        pid = sys_exec(id, argc,  printlocation,  1,  2);
        printf("The pid of the process is %d\n", pid);
        printf("> root@UCAS_OS: ");
    }
}

void 
shell_ps()
{
    sys_ps();
    printf("> root@UCAS_OS: ");
}

int 
shell_waitpid(char *pid)
{

}

int 
shell_kill(char *pid)
{
    pid_t kill_pid = (pid_t)my_atoi(pid);
    int killed;
    killed = sys_kill(kill_pid);
    if (killed)
        printf("The process [%d] has been killed\n", kill_pid);
    else
        printf("Error for syscall kill\n");
    return killed;
}

struct 
cmd_table
{
    char *      cmd_name;
    function    func;
    int         args_num;
}cmd_table[] = 
    {
        {"exec",    &shell_exec,    1 },
        {"wait",    &shell_waitpid, 1 },
        {"kill",    &shell_kill,    1},
        {"ps",      &shell_ps,      0}
    };

int
match_cmd_id(char *cmd)
{
    int i;
    for(i = 0; i < CMD_NUM; i++){
        if(strcmp(cmd, cmd_table[i].cmd_name) == 0){
            return i;
        }
    }
    return -1;
    
}

void 
parse_cmd(char *buf)
{
    char args[cmd_nums][cmd_args];
    // init the cmd args
    int i, j, k;
    for(i = 0; i < cmd_nums; i++)
        for(j = 0; j < cmd_args; j++)
            args[i][j] = 0;
    int cmd_id;
    char *parse = buf;
    i = j = 0;
    // change the cmd into two demesion
    while(parse[j] != 0){
        if(parse[j] != ' '){
            args[i][k++] = parse[j];  
        }else{
            args[i][k] = 0;
            i++;
            k = 0;
        }
        j += 1;
    }
    cmd_id = match_cmd_id(args[0]);
    if (cmd_id < 0){
        printf("Error, unknown cmd\n");
        printf("> root@UCAS: ");
    }else
    if (cmd_table[cmd_id].args_num != i){
        printf("Error, wrong parameters\n");
        printf("> root@UCAS_OS: ");
    }else{
        cmd_table[cmd_id].func(args[1]);
    }
}

int main(void)
{
    sys_move_cursor(0, SHELL_BEGIN);
    printf("------------------- COMMAND -------------------\n");
    printf("> root@UCAS_OS: ");
    static char buf [100];
    int i = 0;
    while (1)
    {
        // TODO [P3-task1]: call syscall to read UART port
        char c = sys_getchar();
        
        // press enter, parse the cmd
        if (c == 255)
            continue;
        if (c == '\r'){
            printf("\n");
            buf[i] = '\0';
            parse_cmd(buf);
            i = 0;
        }else
        // note: backspace maybe 8('\b') or 127(delete)
        if (c == 8 || c == 127){
            buf[--i] = 0;
            c = 8;
            printf("\b");
        }else{
            buf[i++] = c;
            printf("%c", c);
        }
        // TODO [P3-task1]: parse input
        

        // TODO [P3-task1]: ps, exec, kill, clear        
    }

    return 0;
}
